﻿using mozhi.smarterp.Finance.Accounts;
using mozhi.smarterp.Finance.Accounts.Repository;
using mozhi.smarterp.Finance.Banks;
using mozhi.smarterp.Finance.Banks.Repository;
using mozhi.smarterp.Finance.Enums;
using mozhi.smarterp.Finance.Finances.Repository;
using mozhi.smarterp.Finance.Querys;
using Mozhi.Abp.Core.Extensions;
using Mozhi.Abp.Domain.BasicData.Repositories;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Domain.Services;

namespace mozhi.smarterp.Finance.Finances.Services
{
    public class JournalManager : DomainService
    {
        private IJournalRepository _journalRepository;
        private IAccountRepository _accountRepository;
        private IOrganizationRepository _organizationRepository;
        private IBankAccountRepository _bankAccountRepository;
        private ISettlementRepository _settlementRepository;

        public JournalManager(IJournalRepository journalRepository, IAccountRepository accountRepository,
            IOrganizationRepository organizationRepository, IBankAccountRepository bankAccountRepository, ISettlementRepository settlementRepository)
        {
            _journalRepository = journalRepository;
            _accountRepository = accountRepository;
            _organizationRepository = organizationRepository;
            _bankAccountRepository = bankAccountRepository;
            _settlementRepository = settlementRepository;
        }

        public async Task<Journal> Create(Guid id, Guid numberPrefixId, DateTime date)
        {
            var number = await GetNextJournalNumber(numberPrefixId, date.ToPeriod());

            //1.编号是否存在
            await CheckNumberDuplicateAsync(numberPrefixId, number, date);

            return new Journal(id, numberPrefixId, number, date);

        }

        public async Task CheckNumberDuplicateAsync(Guid numberPrefixId, string number, DateTime date, Guid? currentId = null)
        {
            var period = date.ToPeriod();

            var count = await _journalRepository.GetCountAsync(new JournalPageQuery() { NumberPrefixId = numberPrefixId, Number = number, Period = period, ExclusionId = currentId });

            if (count > 0)
                throw new UserFriendlyException($"编号：{number}在期间：{period}已存在", "100000");
        }

        public async Task ChangeItems(Journal journal, List<JournalItem> items)
        {
            //var accountIds = items.Select(x => x.AccountId).Distinct().ToList();

            //var accounts = await _accountRepository.GetListAsync();

            //accounts = accounts.Where(x=>accountIds.Contains(x.Id)).ToList()

            //var bankAccountIds = accounts.Where(x => x.BankAccountId.HasValue).Select(x => x.BankAccountId.Value).Distinct().ToList();

            //var bankAccounts = await _bankAccountRepository.FindAsync(new QueryBase() { Ids = bankAccountIds });

            //foreach (var item in items)
            //{
            //    var matchAccount = accounts.FirstOrDefault(x => x.Id == item.AccountId);
            //    var matchBankAccount = bankAccounts.FirstOrDefault(x => x.Id == matchAccount?.BankAccountId);

            //    //校验科目
            //    CheckAccount(matchAccount, matchBankAccount, (await _organizationRepository.GetAsync()).StandardCurrencyId.Value, item);
            //}

            //journal.ChangeItems(items);
            throw new NotImplementedException();
        }

        public void CheckAccount(Account account, BankAccount bankAccount, Guid baseCurrencyId, JournalItem item)
        {

            //if (account == null)
            //    throw new UserFriendlyException($"行{item.Index}的科目不存在", "100000");

            //if (!account.Activated)
            //    throw new UserFriendlyException($"行{item.Index}的科目已禁用", "100000");

            //if (!account.IsForeignCurrency && item.CurrencyId != baseCurrencyId)
            //    throw new UserFriendlyException($"行{item.Index}的科目为非外币核算，不能录入外币金额", "100000");


            //if (account.BankAccountId.HasValue)
            //{
            //    if (bankAccount?.CurrencyId != item.CurrencyId)
            //        throw new UserFriendlyException($"行{item.Index}的科目为资金科目，不能录入银行账号不同的币别金额", "100000");
            //}
            throw new NotImplementedException();
        }

        public async Task ValidateSettlement(List<int> periods)
        {
            var settlements = await _settlementRepository.FindAsync(new SettlementQuery() { Periods = periods, Closed = true });

            if (settlements.Count > 0)
            {
                var settlementPeriods = settlements.Select(x => x.Period).Distinct().ToList();

                throw new UserFriendlyException($"期间已经结账，不能进行审核和反审核操作：{string.Join(",", settlementPeriods)}", "100000");
            }
        }

        /// <summary>
        /// 获取下一个编码
        /// </summary>
        /// <param name="numberPrefix"></param>
        /// <param name="period"></param>
        /// <returns></returns>
        public async Task<string> GetNextJournalNumber(Guid numberPrefixId, int period)
        {
            var numbers = await _journalRepository.FindNumbersAsync(numberPrefixId, period);

            if (numbers.Count == 0)
                return 1.ToJournalNumber();

            var result = 1;

            //如果编号数量等于最大的编号数，表示没有段号，直接从
            if (numbers.Count == numbers.Max())
                result = numbers.Max() + 1;
            else
            {
                //表示有断号，需要第一个断的号码
                for (var i = 1; i < numbers.Count; i++)
                {
                    if (i != numbers[i - 1])
                    {
                        result = i;
                        break;
                    }
                }
            }
            return result.ToJournalNumber();
        }

        public List<AccountBalance> ConvertToBalance(Journal journal)
        {
            var balances = new List<AccountBalance>();

            if (journal.Items == null || journal.Items.Count == 0)
                return balances;

            journal.Items.ForEach(item =>
            {
                var balance = new AccountBalance(Guid.NewGuid(), item.AccountId, item.CurrencyId, journal.Period, item.DimensionGroupValueId, item.JournalDirection);

                if (balance.Direction == AccountDirectionType.Debit)
                    balance.ChangeCurrentAmount(item.DebitAmount, item.AmountFr, null, null);
                else
                    balance.ChangeCurrentAmount(null, null, item.DebitAmount, item.AmountFr);

                balances.Add(balance);
            });


            return balances;
        }
    }
}
